package com.dffl.es.esstudy.service.impl;

import com.dffl.es.esstudy.page.Page;
import com.dffl.es.esstudy.service.BaseSearchService;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * elasticsearch 搜索引擎
 *
 * @author liwenishan
 */
@Service
public class BaseSearchServiceImpl<T> implements BaseSearchService<T> {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private ElasticsearchTemplate elasticsearchRestTemplate;

    @Override
    public List<T> query(String keyword, Class<T> clazz) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(new QueryStringQueryBuilder(keyword))
                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
                .build();
        return elasticsearchRestTemplate.queryForList(searchQuery, clazz);
    }

    /**
     * 高亮显示
     *
     */
    @Override
    public List<T> queryHit(String keyword, Class<T> clazz, String fieldNames) {
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = createMultiMathQueryBuilder(keyword, fieldNames);

        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(fieldNames);


        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(matchQuery)
                .withHighlightBuilder(highlightBuilder)
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC))
                .build();

        AggregatedPage<T> search = elasticsearchRestTemplate.queryForPage(searchQuery, clazz);

        return search.getContent();
    }

    /**
     * 高亮显示，返回分页
     *
     */
    @Override
    public Page<T> queryHitByPage(int pageNo, int pageSize, String keyword, Class<T> clazz, String fieldNames) {
        // 构造查询条件,使用标准分词器.
        QueryBuilder matchQuery = createMultiMathQueryBuilder(keyword,fieldNames);


        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = createHighlightBuilder(fieldNames);

        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(matchQuery)
                .withHighlightBuilder(highlightBuilder)
                .withPageable(PageRequest.of(pageNo - 1, pageSize))
                .withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC))
                .build();

        AggregatedPage<T> search = elasticsearchRestTemplate.queryForPage(searchQuery, clazz);

        // 返回搜索结果
        List<T> result = search.getContent();
        Long totalCount = search.getTotalElements();
        Page<T> page = new Page<>(pageNo, pageSize, totalCount.intValue());
        page.setList(result);
        return page;
    }

    /**
     * 构造查询条件
     *
     */
    private QueryBuilder createMultiMathQueryBuilder(String keyword, String fieldNames) {
        // 构造查询条件,使用标准分词器.
        return QueryBuilders.multiMatchQuery(keyword, fieldNames.split(","))   // matchQuery(),单字段搜索
                .analyzer("ik_max_word")
                .operator(Operator.OR);
    }

    private QueryBuilder createTermQueryBuilder(String value,String filedName){
        return QueryBuilders.termsQuery(filedName,value);
    }

    /**
     * 构造高亮器
     *
     */
    private HighlightBuilder createHighlightBuilder(String fieldNames) {
        // 设置高亮,使用默认的highlighter高亮器
        HighlightBuilder highlightBuilder = new HighlightBuilder()
                // .field("productName")
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        // 设置高亮字段
        for (String fieldName : fieldNames.split(",")) {
            highlightBuilder.field(fieldName);
        }

        return highlightBuilder;
    }

    /**
     * 处理高亮结果
     *
     */
    private List<Map<String, Object>> getHitList(SearchHits hits) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map;
        for (SearchHit searchHit : hits) {
            map = new HashMap<>();
            // 处理源数据
            map.put("source", searchHit.getSourceAsMap());
            // 处理高亮数据
            Map<String, Object> hitMap = new HashMap<>();
            searchHit.getHighlightFields().forEach((k, v) -> {
                String hight = "";
                for (Text text : v.getFragments()) {
                    hight += text.string();
                }
                hitMap.put(v.getName(), hight);
            });
            map.put("highlight", hitMap);
            list.add(map);
        }
        return list;
    }

    @Override
    public void deleteIndex(String indexName) {
        elasticsearchRestTemplate.deleteIndex(indexName);
    }
}
